//
// Created by martin on 2/8/22.
//

#ifndef MUDUO_EVENTLOOP_H
#define MUDUO_EVENTLOOP_H

#include "muduo/base/noncopyable.h"
#include "muduo/base/Mutex.h"
#include "muduo/base/CurrentThread.h"
#include "muduo/base/Timestamp.h"
#include "muduo/net/TimerId.h"
#include "muduo/net/Callbacks.h"

#include <boost/any.hpp>
#include <vector>
#include <atomic>

namespace muduo
{
namespace net
{

class Channel;
class Poller;
class TimerQueue;

/**
 * Reactor模式， 每个线程最多一个EventLoop (One loop per thread).
 *
 * 接口类, 不要暴露太多细节给客户
 */
class EventLoop : public noncopyable
{
public:
    typedef std::function<void()> Functor;

    EventLoop();
    ~EventLoop(); // force out-line dtor, for std::unique_ptr members.

    /* loop循环, 运行一个死循环.
     * 必须在当前对象的创建线程中运行.
     */
    void loop();

    /*callingPendingFunctors
     * 退出loop循环.
     * 如果通过原始指针(raw pointer)调用, 不是100%线程安全;
     * 为了100%安全, 最好通过shared_ptr<EventLoop>调用
     */
    void quit();

    /*
     * Poller::poll()返回的时间, 通常意味着有数据达到.
     * 对于PollPoller, 是调用完poll(); 对于EPollPoller, 是调用完epoll_wait()
     */
    Timestamp pollReturnTime() const { return pollReturnTime_; }

    /* 获取loop循环次数 */
    int64_t iterator() const { return iteration_; }

    /*
     * 在loop线程中, 立即运行回调cb.
     * 如果没在loop线程, 就会唤醒loop, (排队)运行回调cb.
     * 如果用户在同一个loop线程, cb会在该函数内运行; 否则， 会在loop线程中排队运行.
     * 因此, 在其他线程中调用该函数是安全的.
     */
    void runInLoop(Functor cb);

    /* 排队回调cb进loop线程.
     * 回调cb在loop中完成polling后运行.
     * 从其他线程调用是安全的.
     */
    void queueInLoop(Functor cb);

    /* 排队的回调cb个数 */
    size_t queueSize() const;

    // timers

    /*
     * 在指定时间点运行回调cb.
     * 从其他线程调用安全.
     */
    TimerId runAt(Timestamp time, TimerCallback cb);

    /*
     * 在当前时间点+delay延时后运行回调cb.
     * 从其他线程调用安全.
     */
    TimerId runAfter(double delay, TimerCallback cb);

    /*
     * 每隔interval sec周期运行回调cb.
     * 从其他线程调用安全.
     */
    TimerId runEvery(double interval, TimerCallback cb);

    /*
     * 取消定时器, timerId唯一标识定时器Timer
     * 从其他线程调用安全.
     */
    void cancel(TimerId timerId);

    // internal usage

    /* 唤醒loop线程, 没有事件就绪时, loop线程可能阻塞在poll()/epoll_wait() */
    void wakeup();
    /* 更新Poller监听的channel, 只能在channel所属loop线程中调用 */
    void updateChannel(Channel* channel);
    /* 移除Poller监听的channel, 只能在channel所属loop线程中调用 */
    void removeChannel(Channel* channel);
    /* 判断Poller是否正在监听channel, 只能在channel所属loop线程中调用 */
    bool hasChannel(Channel* channel);

    // pid_t threadId() const { return threadId_; }
    /* 断言当前线程是创建当前对象的线程, 如果不是就终止程序(LOG_FATAL) */
    void assertInLoopThread()
    {
        if (!isInLoopThread())
        {
            abortNotInLoopThread();
        }
    }
    /* 判断前线程是否创建当前对象的线程.
     * threadId_是创建当前EventLoop对象时, 记录的线程tid
     */
    bool isInLoopThread() const
    { return threadId_ == CurrentThread::tid(); }

    /*
     * 判断是否有待调用的回调函数(pending functor).
     * 由其他线程调用runAt/runAfter/runEvery, 会导致回调入队列待调用.
     */
    bool callingPendingFunctors() const
    { return callingPendingFunctors_; }

    /*
     * 判断loop线程是否正在处理事件, 执行事件回调.
     * loop线程正在遍历,执行激活channels时, eventHandling_会置位; 其余时候, 会清除.
     */
    bool eventHandling() const
    { return eventHandling_; }
    /* context_ 用于应用程序传参, 由网络库用户定义数据 */
    void setContext(const boost::any& context)
    { context_ = context; }
    const boost::any& getContext() const
    { return context_; }
    boost::any* getMutableContext()
    { return &context_; }

    /* 获取当前线程的EventLoop对象指针 */
    static EventLoop* getEventLoopOfCurrentThread();

private:
    /* 终止程序(LOG_FATAL), 当前线程不是创建当前EventLoop对象的线程时,
     * 由assertInLoopThread()调用  */
    void abortNotInLoopThread();
    /* 唤醒所属loop线程, 也是wakeupFd_的事件回调 */
    void handleRead(); // waked up
    /* 处理pending函数 */
    void doPendingFunctors();
    /* 打印激活通道的事件信息, 用于debug */
    void printActiveChannels() const; // DEBUG

    typedef std::vector<Channel*> ChannelList;

    bool looping_;                /* atomic, true表示loop循环执行中 */
    std::atomic<bool> quit_;      /* loop循环退出条件 */
    bool eventHandling_;          /* atomic, true表示loop循环正在处理事件回调 */
    bool callingPendingFunctors_; /* atomic, true表示loop循环正在调用pending函数 */
    int64_t iteration_;           /* loop迭代次数 */
    const pid_t threadId_;                   /* 线程id, 对象构造时初始化 */
    Timestamp pollReturnTime_;               /* poll()返回时间点 */
    std::unique_ptr<Poller> poller_;         /* 轮询器, 用于监听事件 */
    std::unique_ptr<TimerQueue> timerQueue_; /* 定时器队列 */
    int wakeupFd_;                           /* 唤醒loop线程的eventfd */
    /* 用于唤醒loop线程的channel.
     * 不像TimerQueue是内部类, 不应该暴露Channel给客户. */
    std::unique_ptr<Channel> wakeupChannel_;
    boost::any context_;            /* 用于应用程序通过当前对象传参的变量, 由用户定义数据 */

    /* 临时辅助变量 */
    ChannelList activeChannels_;    /* 激活事件的通道列表 */
    Channel* currentActiveChannel_; /* 当前激活的通道, 即正在调用事件回调的通道 */

    mutable MutexLock mutex_;
    /* 待调用函数列表, 存放其他线程(非当前loop线程)调用 runAt/runAfter/runEvery, 而要运行的函数 */
    std::vector<Functor> pendingFunctors_ GUARDED_BY(mutex_);
};

} // namespace net
} // namespace muduo

#endif //MUDUO_EVENTLOOP_H
